package com.pt25.base.util;

import lombok.Getter;
import okhttp3.*;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class HttpUtil {

    public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");

    @Getter
    private static final OkHttpClient client;

    static {
        ConnectionPool pool = new ConnectionPool(10, 5, TimeUnit.MINUTES);

        Dispatcher dispatcher = new Dispatcher();
        dispatcher.setMaxRequests(500); // 设置最大同时请求数
        dispatcher.setMaxRequestsPerHost(100); // 设置每个主机的最大请求数

        client = new OkHttpClient.Builder()
                .connectionPool(pool)
                .connectTimeout(5, TimeUnit.SECONDS)
                .writeTimeout(5, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .dispatcher(dispatcher)
                .build();
    }


    public static String get(String url) throws IOException {
        return get(url, null);
    }

    public static String get(String url, long connectTimeout, long writeTimeout, long readTimeout) throws IOException {
        return get(url, null, connectTimeout, writeTimeout, readTimeout);
    }

    public static String get(String url, Map<String, String> headers) throws IOException {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url);
        addHeaders(requestBuilder, headers);

        Request request = requestBuilder.build();
        Response response = client.newCall(request).execute();
        return handleResponse(response);
    }


    public static String get(String url, Map<String, String> headers, long connectTimeout, long writeTimeout, long readTimeout) throws IOException {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url);
        addHeaders(requestBuilder, headers);

        OkHttpClient customClient = getOkHttpClient(connectTimeout, writeTimeout, readTimeout);

        Request request = requestBuilder.build();
        Response response = customClient.newCall(request).execute();
        return handleResponse(response);
    }

    public static String post(String url, String params) throws IOException {
        return post(url, null, params);
    }

    public static String post(String url, String params, long connectTimeout, long writeTimeout, long readTimeout) throws IOException {
        return post(url, null, params, connectTimeout, writeTimeout, readTimeout);
    }

    public static String post(String url, Map<String, String> headers, String params) throws IOException {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .post(getRequestBody(params));
        addHeaders(requestBuilder, headers);

        Request request = requestBuilder.build();
        Response response = client.newCall(request).execute();
        return handleResponse(response);
    }


    public static String post(String url, Map<String, String> headers, String params, long connectTimeout, long writeTimeout, long readTimeout) throws IOException {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .post(getRequestBody(params));
        addHeaders(requestBuilder, headers);

        OkHttpClient customClient = getOkHttpClient(connectTimeout, writeTimeout, readTimeout);

        Request request = requestBuilder.build();
        Response response = customClient.newCall(request).execute();
        return handleResponse(response);
    }

    /**
     * 流式输出
     */
    public static void streamPost(String url, Map<String, String> headers, String params, Callback callback, long connectTimeout, long writeTimeout, long readTimeout) {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .post(getRequestBody(params));
        addHeaders(requestBuilder, headers);
        Request request = requestBuilder.build();
        OkHttpClient customClient = getOkHttpClient(connectTimeout, writeTimeout, readTimeout);
        customClient.newCall(request).enqueue(callback);
    }

    public static String put(String url, String params) throws IOException {
        return put(url, null, params);
    }

    public static String put(String url, String params, long connectTimeout, long writeTimeout, long readTimeout) throws IOException {
        return put(url, null, params, connectTimeout, writeTimeout, readTimeout);
    }

    public static String put(String url, Map<String, String> headers, String params) throws IOException {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .put(getRequestBody(params));
        addHeaders(requestBuilder, headers);

        Request request = requestBuilder.build();
        Response response = client.newCall(request).execute();
        return handleResponse(response);
    }


    public static String put(String url, Map<String, String> headers, String params, long connectTimeout, long writeTimeout, long readTimeout) throws IOException {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .put(getRequestBody(params));
        addHeaders(requestBuilder, headers);

        OkHttpClient customClient = getOkHttpClient(connectTimeout, writeTimeout, readTimeout);

        Request request = requestBuilder.build();
        Response response = customClient.newCall(request).execute();
        return handleResponse(response);
    }

    public static String delete(String url) throws IOException {
        return delete(url, null, null);
    }

    public static String delete(String url, long connectTimeout, long writeTimeout, long readTimeout) throws IOException {
        return delete(url, null, null, connectTimeout, writeTimeout, readTimeout);
    }

    public static String delete(String url, Map<String, String> headers, String params) throws IOException {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .delete(getRequestBody(params));
        addHeaders(requestBuilder, headers);

        Request request = requestBuilder.build();
        Response response = client.newCall(request).execute();
        return handleResponse(response);
    }

    public static String delete(String url, Map<String, String> headers, String params, long connectTimeout, long writeTimeout, long readTimeout) throws IOException {
        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .delete(getRequestBody(params));
        addHeaders(requestBuilder, headers);

        OkHttpClient customClient = getOkHttpClient(connectTimeout, writeTimeout, readTimeout);

        Request request = requestBuilder.build();
        Response response = customClient.newCall(request).execute();
        return handleResponse(response);
    }

    private static OkHttpClient getOkHttpClient(long connectTimeout, long writeTimeout, long readTimeout) {
        return client.newBuilder()
                .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
                .writeTimeout(writeTimeout, TimeUnit.MILLISECONDS)
                .readTimeout(readTimeout, TimeUnit.MILLISECONDS)
                .build();
    }

    private static RequestBody getRequestBody(String params) {
        if (null != params) {
            return RequestBody.create(JSON, params);
        }
        return RequestBody.create(JSON, JsonUtil.toJson(new HashMap<>()));
    }

    private static String handleResponse(Response response) throws IOException {
        if (response.isSuccessful()) {
            assert response.body() != null;
            return response.body().string();
        } else {
            throw new IOException("Unexpected code " + response);
        }
    }

    private static void addHeaders(Request.Builder requestBuilder, Map<String, String> headers) {
        if (headers != null) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                requestBuilder.addHeader(entry.getKey(), entry.getValue());
            }
        }
    }
}